# -*-coding:utf-8-*-

from tornado.gen import coroutine, Return
from bson.objectid import ObjectId
from utils.misc import limit_update_scope


class BaseDelegateImpl(object):
    def __init__(self, *args, **kwargs):
        self._handler = kwargs['handler']
        self._mqtt = self._handler.mqtornado
        self._daos = self._handler.settings['daos_async']
        self._logger = self._handler.logger
        if hasattr(self._handler, 'user_id'):
            self._uid = self._handler.user_id
        self._app = self._handler.app
        self._respond_error_func = self._handler._delegate_respond_error

    @coroutine
    def _update_specifics(self, dao_name, _id, update):
        filter_cond = {'_id': ObjectId(_id)}
        limited_update = limit_update_scope(update)
        result = yield self._daos[dao_name].update_one(filter_cond, limited_update)
        raise Return(1 == result.matched_count)

    @coroutine
    def _update_user_specifics(self, uid, update):
        if uid is None:
            uid = self._uid
        result = yield self._update_specifics('users', uid, update)
        raise Return(result)

    @coroutine
    def _update_device_specifics(self, did, update):
        result = yield self._update_specifics('devices', did, update)
        raise Return(result)

    @coroutine
    def _update_order_specifics(self, oid, update):
        result = yield self._update_specifics('orders', oid, update)
        raise Return(result)

    @coroutine
    def _update_product_specifics(self, pid, update):
        result = yield self._update_specifics('products', pid, update)
        raise Return(result)

    @coroutine
    def _get_specifics(self, dao_name, _id):
        filter_cond = {'_id': ObjectId(_id)}
        projection = {'_id': 0, 'specifics': 1}
        result = yield self._daos[dao_name].find_one(filter_cond, projection)
        if not result or 'specifics' not in result:
            result = None
        else:
            result = result['specifics']
        raise Return(result)

    @coroutine
    def _get_user_specifics(self, **kwargs):
        if 0 == len(kwargs):
            kwargs['user_id'] = self._uid
        kwargs['projection'] = {'specifics': 1}
        result = yield self._daos['users'].get_user_raw(self._app, **kwargs)
        if not result or 'specifics' not in result:
            result = None
        else:
            user_id = str(result.pop('_id'))
            result = result['specifics']
            result['user_id'] = user_id
        raise Return(result)

    @coroutine
    def _get_user_role_names(self, **kwargs):
        if 0 == len(kwargs):
            kwargs['user_id'] = self._uid
        kwargs['projection'] = {'_id': 0, 'roles': 1}
        result = yield self._daos['users'].get_user_raw(self._app, **kwargs)
        if not result:
            raise Return([])
        roles_of_user = result['roles']
        result = yield self._daos['roles'].get_role_list_by_ids(roles_of_user)
        role_names = [x['name'] for x in result]
        raise Return(role_names)

    @coroutine
    def _get_user_common_info(self, **kwargs):
        if 0 == len(kwargs):
            kwargs['user_id'] = self._uid
        kwargs['projection'] = {'_id': 0, 'username': 1, 'phone': 1, 'avatar': 1, 'nickname': 1, 'name': 1, 'tags': 1}
        result = yield self._daos['users'].get_user_raw(self._app, **kwargs)
        if not result:
            result = None
        raise Return(result)

    @coroutine
    def _get_device_specifics(self, did):
        result = yield self._get_specifics('devices', did)
        raise Return(result)

    @coroutine
    def _get_order_specifics(self, oid):
        result = yield self._get_specifics('orders', oid)
        raise Return(result)

    @coroutine
    def _get_product_specifics(self, pid):
        result = yield self._get_specifics('products', pid)
        raise Return(result)

    def _publish(self, topic, payload):
        self._mqtt.publish(topic, payload)

    def _respond_error(self, error_code, msg=None):
        self._respond_error_func(error_code, msg)

    def _extract_fields(self, src, required_fields=None, optional_fields=None):
        return self._handler.extract_fields(src, required_fields, optional_fields)

    def _exclude_fields(self, src, exclusive_fields):
        self._handler.exclude_fields(src, exclusive_fields)
